package com.common.repository;

import com.common.dao.BaseDao;
import com.common.entity.SupperEntity;
import com.common.exception.ErrorException;
import com.common.mysql.KeyAndValuePair;
import com.common.mysql.Where;
import com.common.mysql.convert.AbstractConvert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class BaseRepository<I, E extends SupperEntity<I>, D extends BaseDao<I, E>> {


    @Autowired
    private D dao;

    protected Class<E> entityClass;

    public void setEntityClass(Class<E> entityClass) {
        this.entityClass = entityClass;
    }

    /**
     * 查询全部
     *
     * @param tableName
     * @param keyAndValuePairList
     * @param <E>
     * @return
     */
    public <E> List<E> searchAll(String tableName, List<KeyAndValuePair> keyAndValuePairList) {
        List<Map<String, Object>> searchResult = dao.searchAll(tableName, keyAndValuePairList);
        List<E> result = new LinkedList<>();
        convertMapListToEntityList(searchResult, result);
        return result;
    }

    /**
     * 将list中map类型的集合转换为对应范型<E>类型的对象
     *
     * @param searchResult
     * @param result
     * @param <E>
     */
    private <E> void convertMapListToEntityList(List<Map<String, Object>> searchResult, List<E> result) {
        E entity = null;
        for (int i = 0; i < searchResult.size(); i++) {
            Map<String, Object> resultMap = searchResult.get(i);
            entity = (E) getEntityInstance();
            convertMapToEntity(resultMap, entity);
            if (ObjectUtils.isEmpty(entity)) {
                continue;
            }
            result.add(entity);
        }
    }

    /**
     * 将map集合转为entity类型
     *
     * @param map
     * @param entity
     * @param <E>
     */
    private <E> E convertMapToEntity(Map<String, Object> map, E entity) {
        if (CollectionUtils.isEmpty(map)) {
            return null;
        }
        for (Class entityCLass = entity.getClass(); !Object.class.equals(entityCLass); entityCLass = entityCLass.getSuperclass()) {
            Field[] fields = entityCLass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                field.setAccessible(true);
                com.common.annotation.Field fieldAnnotation = field.getAnnotation(com.common.annotation.Field.class);
                String name = ObjectUtils.isEmpty(fieldAnnotation) ? field.getName() : fieldAnnotation.alias();
                Object value = map.get(name);
                if (ObjectUtils.isEmpty(value)) {
                    continue;
                }
                try {
                    Object convertFiledName = null;
                    if (!ObjectUtils.isEmpty(fieldAnnotation)) {
                        Class<? extends AbstractConvert> convert = fieldAnnotation.convert();
                        if (!convert.equals(AbstractConvert.class)) {
                            AbstractConvert abstractConvert = convert.newInstance();
                            convertFiledName = abstractConvert.convert(value);
                        } else {
                            convertFiledName = value;
                        }
                    } else {
                        convertFiledName = value;
                    }
                    field.set(entity, convertFiledName);
                } catch (IllegalAccessException | InstantiationException e) {
                    throw new ErrorException(e.getMessage());
                }
            }

        }
        return entity;
    }

    /**
     * 获取entity实例
     *
     * @return
     */
    private E getEntityInstance() {
        try {
            return getEntityClass().newInstance();
        } catch (Exception e) {
            throw new ErrorException(e.getMessage());
        }
    }

    /**
     * 获取entity类
     *
     * @return
     */
    protected Class<E> getEntityClass() {
        Class<E> entityClass = null;
        Type genericSuperclass = getClass().getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type entityType = parameterizedType.getActualTypeArguments()[1];
            entityClass = (Class<E>) entityType;
        }
        return entityClass;
    }

    /**
     * w
     * 查询单个
     *
     * @param id
     * @param tableName
     * @param fields
     * @return
     */
    public E getById(I id, String tableName, List<KeyAndValuePair> fields) {
        Map<String, Object> resultMap = dao.getById(id, tableName, fields);
        E entity = getEntityInstance();
        convertMapToEntity(resultMap, entity);
        return entity;
    }

    /**
     * 包含条件查询
     *
     * @param tableName
     * @param fields
     * @param where
     * @return
     */
    public List<E> search(String tableName, List<KeyAndValuePair> fields, Where where) {
        List<KeyAndValuePair> searchFields = where.getKeyAndValuePairs();
        fields.addAll(searchFields);
        List<Map<String, Object>> resultList = dao.searchAll(tableName, fields);
        List<E> result = new LinkedList<>();
        convertMapListToEntityList(resultList, result);
        return result;
    }

    public int update(I id, String tableName, List<KeyAndValuePair> fields) {
        return dao.update(id, tableName, fields);
    }

    public int delete(I id, String tableName) {
        return dao.delete(id, tableName);
    }

    public int add(String tableName, List<KeyAndValuePair> keyAndValuePairList) {

        return dao.add(tableName, keyAndValuePairList);
    }

    public E searchOne(String tableName, List<KeyAndValuePair> fields, Where where) {
        List<KeyAndValuePair> searchFields = where.getKeyAndValuePairs();
        fields.addAll(searchFields);
        Map<String, Object> result = dao.searchOne(tableName, fields);
        E entity = getEntityInstance();
        return convertMapToEntity(result, entity);
    }

    public int count(String tableName, Where where) {
        List<KeyAndValuePair> fields = where.getKeyAndValuePairs();
        return dao.count(tableName, fields);
    }
}
